---@class TBS.Battle
local Battle = TBS.CreateSingleton("Battle")
local this = Battle
local specialSkillCfgList = {}
function Battle.Start()
    if this.isStart then
        this.OnDestroy()
    end
    this.OnCreate()
end

function Battle.Leave()
    this.OnDestroy()
    FireEvent(TBS.Config.Event.BattleLeave)
end

function Battle.OnCreate()
    this.isStart = true
    this.isDebug = false
    this.isDebugPrint = true
    this.isBattleFinished = false
    this.updateCallbackList = {}
    this.lateUpdateCallbackList = {}
    this.delayCallbackList = {}
    this.groupPositionList = {}
    this.leaderPosition = {}
    this.bossPosition = {x = 0,y = 0}
    this.MAX_TEAM = 4
    this.BOSS_GROUP = 5
    this.battleTime = 0
    this.battleFrame = 0
    this.uniqueId = 0
    this.resultType = nil
    ---@type Transform
    this.effectParent = nil
    this.isLoadCameraDone = false
    TBS.ActorMgr.OnCreate()
    TBS.PoolMgr.OnCreate()
    TBS.EffectMgr.OnCreate()
    TBS.BufferMgr.OnCreate()
    TBS.RuleMgr.OnCreate()
    TBS.CameraMgr.OnCreate()
    TBS.ReportMgr.OnCreate()
    this.StartUpdateTime()
end
function Battle.OnDestroy()
    if not this.isStart then
        return
    end
    this.isStart = false
    this.EndUpdateTime()
    TBS.ActorMgr.OnDestroy()
    TBS.EffectMgr.OnDestroy()
    TBS.BufferMgr.OnDestroy()
    TBS.RuleMgr.OnDestroy()
    TBS.CameraMgr.OnDestroy()
    TBS.ReportMgr.OnDestroy()
    --PoolMgr保证在最后释放
    TBS.PoolMgr.OnDestroy()
    this.updateCallbackList = nil
    this.lateUpdateCallbackList = nil
    this.delayCallbackList = nil
    this.groupPositionList = nil
    this.effectTemplate = nil
    this.effectParent = nil
    --utimer.remove(this.finishedDelayTimerId)
    --this.finishedDelayTimerId = nil
end
function Battle.Restart(cmd)
    log("Battle.Restart "..tostring(this.isStart))
    if not this.isStart then
        this.Start()
    end
    TBS.ActorMgr.OnDestroy()
    TBS.ActorMgr.OnCreate()
    TBS.ReportMgr.InitReport(cmd)
    if this.isLoadCameraDone then
        TBS.RuleMgr.StartFight()
    end
    this.battleFrame = 0
    FireEvent(TBS.Config.Event.BattleRestart)
end
function Battle.GetUniqueId()
    this.uniqueId = this.uniqueId + 1
    return this.uniqueId
end
function Battle.BattleFinished(resultType,reset)
    print("战斗结束resultType:"..resultType)
    this.resultType = resultType
    --utimer.remove(this.finishedDelayTimerId)
    this.ShowBattleFinishedResult()
    --if reset then
    --    this.finishedDelayTimerId = utimer.delayCall(this.ShowBattleFinishedResult,2000)
    --end
end
function Battle.ShowBattleFinishedResult()
    --[[if this.resultType == TBS.Config.BattleResultType.groupAllDie then
        UISysTips.AddMsg("战场正在重置")
    elseif this.resultType == TBS.Config.BattleResultType.bossDie then
        UISysTips.AddMsg("战场正在重置")
    end
    this.Restart("")]]
    FireEvent(TBS.Config.Event.BattleFinished,this.resultType)
end
function Battle.RegisterUpdateCallback(callback,tb)
    for k,v in pairs(this.updateCallbackList) do
        if v.callback == callback and v.tb == tb then
            return
        end
    end
    table.insert(this.updateCallbackList,{callback = callback,tb = tb})
end
function Battle.RegisterLateUpdateCallback(callback,tb)
    for k,v in pairs(this.lateUpdateCallbackList) do
        if v.callback == callback and v.tb == tb then
            return
        end
    end
    table.insert(this.lateUpdateCallbackList,{callback = callback,tb = tb})
end
function Battle.IsInBattle()
    return this.isStart
end
function Battle.DelayCall(delaySeconds,callback,tb)
    for k,v in pairs(this.delayCallbackList) do
        if v.callback == callback and v.tb == tb then
            return
        end
    end
    local uniqueId = this.GetUniqueId()
    this.delayCallbackList[uniqueId] = {delay = delaySeconds,callback = callback,tb = tb,time = 0,id = uniqueId}
    return uniqueId
end
function Battle.RemoveDelayCall(id)
    if id == nil then return end
    this.delayCallbackList[id] = nil
end
function Battle.Update()
    local dt = Time.deltaTime
    this.battleTime = this.battleTime + dt
    this.battleFrame = this.battleFrame + 1
    --delay
    local _temp = TablePool.Get()
    for k,v in pairs(this.delayCallbackList) do
        v.time = v.time + dt
        if v.time >= v.delay then
            v.callback(v.tb)
            table.insert(_temp,v)
        end
    end
    for k,v in pairs(_temp) do
        this.delayCallbackList[v.id] = nil
    end
    TablePool.ReleaseDeeper(_temp,false)
    --update
    for k,v in pairs(this.updateCallbackList) do
        if v.tb then
            v.callback(v.tb,dt)
        else
            v.callback(dt)
        end
    end

    --late update
    for k,v in pairs(this.lateUpdateCallbackList) do
        if v.tb then
            v.callback(v.tb,dt)
        else
            v.callback(dt)
        end
    end
end
function Battle.StartUpdateTime()
    this.EndUpdateTime()
    this.updateTimerId = utimer.frameCall(this.Update,-1)
end
function Battle.EndUpdateTime()
    if this.updateTimerId then
        utimer.remove(this.updateTimerId)
        this.updateTimerId = nil
    end
end
function Battle.SetGroupPosition(groupId,index,x,y)
    local _list = this.groupPositionList[groupId]
    if not _list then
        _list = {}
        this.groupPositionList[groupId] = _list
    end
    _list[index] = {x = x,y = y}
    local actors = TBS.ActorMgr.GetGroupActors(groupId)
    if not actors then return end
    local actor = actors[index]
    if not actor then
        return
    end
    actor:SetPos(x,y)
end
function Battle.GetGroupPosition(groupId,index)
    local _list = this.groupPositionList[groupId]
    if not _list then return 0,0 end
    local p = _list[index]
    if not p then return 0,0 end
    return p.x,p.y
end
function Battle.SetLeaderPosition(groupId,x,y)
    local _list = this.leaderPosition[groupId]
    if not _list then
        _list = {}
        this.leaderPosition[groupId] = _list
    end
    _list.x = x
    _list.y = y
    local leader = TBS.ActorMgr.GetGroupLeader(groupId)
    if not leader then
        return
    end
    leader:SetPos(x,y)
end
function Battle.GetAllLeaderCenterPosition()
    local x = 0
    local y = 0
    for k,v in pairs(this.leaderPosition) do
        x = x + v.x
        y = y + v.y
    end
    return x/4,y/4
end
function Battle.GetLeaderPosition(groupId)
    local p = this.leaderPosition[groupId]
    if not p then return 0,0 end
    return p.x,p.y
end
function Battle.SetBossPosition(x,y)
    this.bossPosition.x = x
    this.bossPosition.y = y
    local boss = TBS.ActorMgr.GetBoss()
    if not boss then return end
    boss:SetPos(x,y)
end
function Battle.GetBossPosition()
    return this.bossPosition.x,this.bossPosition.y
end
function Battle.SetEffectRoot(parent)
    this.effectParent = parent
end
function Battle.FGUIToScenePoint(x,y)
    x,y = Util.FGUILocalToScreen(FairyGUI.GRoot.inst,x,y,0,0)
    return this.ScreenToScenePoint(x,y,0)
end
---@return number,number,number
function Battle.SceneToScreenPoint(x,y,z)
    x,y,z = Util.TransformPoint(this.effectParent,x,y,z,0,0,0)
    x,y,z = Util.WorldToScreenPoint(TBS.CameraMgr.camera,x,y,z,0,0,0)
    return x,y,z
end
---@return number,number,number
function Battle.ScreenToScenePoint(x,y,z)
    z = 0
    x,y,z = Util.ScreenToWorldPoint(TBS.CameraMgr.camera,x,y,z,0,0,0)
    x,y,z = Util.InverseTransformPoint(this.effectParent,x,y,z,0,0,0)
    return x,y,z
end
function Battle.AddToScene(go)
    if not go then return end
    go.transform:SetParent(this.effectParent,false)
end
function Battle.LoadCameraDone()
    this.isLoadCameraDone = true
    FireEvent(TBS.Config.Event.BattleLoadDone)
    --TBS.RuleMgr.StartFight()
end
function Battle.GetSpecialSkill(heroIdList)
    if table.getn(specialSkillCfgList) == 0 then
        local cfg = dataTable.getDataTable("t_collocationskill")
        for k,v in pairs(cfg) do
            if v.f_Collocation ~= "" then
                for index,h in pairs(v.f_Collocation) do
                    local heroList = specialSkillCfgList[v.f_Id]
                    if not heroList then
                        heroList = {}
                        specialSkillCfgList[v.f_Id] = heroList
                    end
                    heroList[h[1]] = h[2]
                end
            end
        end
    end
    local tb = {}
    for k,v in pairs(heroIdList) do
        local cfg = dataTable.getDataTableByStringId("t_hero",v)
        local _type = cfg.f_HeroType
        if tb[_type] then
            tb[_type] = tb[_type] + 1
        else
            tb[_type] = 1
        end
    end
    local find = false
    local skillId = 0
    for sId,v in pairs(specialSkillCfgList) do
        for _type,num in pairs(v) do
            if tb[_type] ~= num then
                find = false
                break
            else
                find = true
            end
        end
        if find then
            skillId = sId
            break
        end
    end
    return skillId
end
